package org.vaadinpa.data;

import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.vaadinpa.data.Fleet.FleetOrder;
import org.vaadinpa.gui.VaadinPA;

public class BattleNewsItem extends NewsItem {

	// public Set<Planet> affectedPlanets = new HashSet<Planet>();

	private Map<FleetOrder, Set<Fleet>> participatingFleets = new HashMap<FleetOrder, Set<Fleet>>();
	private Map<Fleet, LinkedHashMap<Ship, Integer>> fleetToShipsBefore = new HashMap<Fleet, LinkedHashMap<Ship, Integer>>();
	private Map<Fleet, LinkedHashMap<Ship, Integer>> fleetToShipsAfter = new HashMap<Fleet, LinkedHashMap<Ship, Integer>>();

	private Map<Resource, Integer> roidsBefore = new HashMap<Resource, Integer>();
	private Map<Resource, Integer> roidsAfter = new HashMap<Resource, Integer>();
	private Map<Planet, Map<Resource, Integer>> roidsTaken = new HashMap<Planet, Map<Resource, Integer>>();

	private Planet targetPlanet;

	public final int id;

	public BattleNewsItem(Planet where, int id) {
		super("<b>Battle Report</b>", "");
		this.id = id;

		targetPlanet = where;

		participatingFleets.put(FleetOrder.DEFEND, new HashSet<Fleet>());
		participatingFleets.put(FleetOrder.ATTACK, new HashSet<Fleet>());
	}

	@Override
	public int hashCode() {
		return id;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null || !(obj instanceof BattleNewsItem)) {
			return false;
		}

		return ((BattleNewsItem) obj).id == id;
	}

	@Override
	public String produceHTML() {

		Planet viewingPlanet = VaadinPA.getPlanet();

		StringBuilder html = new StringBuilder();

		html.append("<b>Target Planet:</b> " + targetPlanet.name + " "
				+ targetPlanet.coords.toString().replaceAll("\n", "") + "<br/>");
		html.append("<b>Attacking fleets:</b> " + participatingFleets.get(FleetOrder.ATTACK).size() + "<br/>");
		html.append("<b>Defending fleets:</b> " + participatingFleets.get(FleetOrder.DEFEND).size() + "<br/>");
		html.append("<br/>");
		html.append("Detailed report:" + "<br/>");

		html.append("<table width=600px border=1>");

		html.append("<tr>");

		html.append("<td>Ship</td>");
		html.append("<td>tot ATT</td>");
		html.append("<td>own ATT</td>");
		html.append("<td>tot DEF</td>");
		html.append("<td>own DEF</td>");
		html.append("<td>attackers killed</td>");
		html.append("<td>defenders killed</td>");
		html.append("<td>you lost</td>");

		html.append("</tr>");

		for (Ship s : Ship.getAvailableShips()) {

			int totalAttackers = 0;
			int ownAttackers = 0;
			int totalDefenders = 0;
			int ownDefenders = 0;

			for (Fleet f : participatingFleets.get(FleetOrder.ATTACK)) {
				int ships = fleetToShipsBefore.get(f).get(s);

				if (viewingPlanet.owns(f)) {
					ownAttackers += ships;
				}
				totalAttackers += ships;
			}
			for (Fleet f : participatingFleets.get(FleetOrder.DEFEND)) {
				int ships = fleetToShipsBefore.get(f).get(s);

				if (viewingPlanet.owns(f)) {
					ownDefenders += ships;
				}
				totalDefenders += ships;
			}

			int totalAttackersLeft = 0;
			int totalDefendersLeft = 0;
			int ownAttackersLeft = 0;
			int ownDefendersLeft = 0;
			for (Fleet f : participatingFleets.get(FleetOrder.ATTACK)) {
				int ships = fleetToShipsAfter.get(f).get(s);

				if (viewingPlanet.owns(f)) {
					ownAttackersLeft += ships;
				}
				totalAttackersLeft += ships;
			}
			for (Fleet f : participatingFleets.get(FleetOrder.DEFEND)) {

				int ships = fleetToShipsAfter.get(f).get(s);

				if (viewingPlanet.owns(f)) {
					ownDefendersLeft += ships;
				}
				totalDefendersLeft += ships;
			}

			html.append("<tr>");

			html.append("<td>" + s.getName() + "</td>");
			html.append("<td>" + totalAttackers + "</td>");
			html.append("<td>" + ownAttackers + "</td>");
			html.append("<td>" + totalDefenders + "</td>");
			html.append("<td>" + ownDefenders + "</td>");
			html.append("<td>" + (totalAttackers - totalAttackersLeft) + "</td>");
			html.append("<td>" + (totalDefenders - totalDefendersLeft) + "</td>");

			int thisPlanetLost = ownAttackers - ownAttackersLeft + ownDefenders - ownDefendersLeft;
			html.append("<td>" + thisPlanetLost + "</td>");

			html.append("</tr>");
		}

		html.append("<tr>");
		html.append("<td>&nbsp;</td>");
		html.append("<td></td>");
		html.append("<td></td>");
		html.append("<td></td>");
		html.append("<td></td>");
		html.append("<td></td>");
		html.append("<td></td>");
		html.append("<td></td>");
		html.append("</tr>");

		html.append("<tr>");
		html.append("<td>Roid type</td>");
		html.append("<td>Available roids</td>");
		html.append("<td>Total roids taken</td>");
		html.append("<td>You took</td>");
		html.append("<td></td>");
		html.append("<td></td>");
		html.append("<td></td>");
		html.append("<td></td>");
		html.append("</tr>");

		for (Resource r : Resource.values()) {
			html.append("<tr>");
			html.append("<td>" + r.name() + "</td>");
			html.append("<td>" + roidsBefore.get(r) + "</td>");
			html.append("<td>" + (roidsBefore.get(r) - roidsAfter.get(r)) + "</td>");
			html.append("<td>" + roidsTaken.get(viewingPlanet).get(r) + "</td>");
			html.append("<td></td>");
			html.append("<td></td>");
			html.append("<td></td>");
			html.append("<td></td>");
			html.append("</tr>");
		}

		html.append("</table>");

		return html.toString();
	}

	public void addShips(Planet p, Fleet fleet, boolean beforeBattle) {

		if (beforeBattle) {
			participatingFleets.get(fleet.currentOrder).add(fleet);

			Map<Resource, Integer> resMap = new HashMap<Resource, Integer>();
			for (Resource r : Resource.values()) {
				resMap.put(r, 0);
			}
			roidsTaken.put(p, resMap);
		}

		LinkedHashMap<Ship, Integer> copyOfFleet = new LinkedHashMap<Ship, Integer>();
		for (Ship s : Ship.getAvailableShips()) {
			copyOfFleet.put(s, fleet.get(s));
		}

		Map<Fleet, LinkedHashMap<Ship, Integer>> m = beforeBattle ? fleetToShipsBefore : fleetToShipsAfter;
		m.put(fleet, copyOfFleet);
	}

	public void fillRoids(boolean before) {

		Map<Resource, Integer> m = before ? roidsBefore : roidsAfter;

		for (Resource r : Resource.values()) {

			if (targetPlanet.roids.get(r) == null) {
				m.put(r, 0);
			} else {
				m.put(r, targetPlanet.roids.get(r));
			}
		}
	}

	public void addTakenRoids(Resource r, int num, Planet taker) {

		int newVal = num + roidsTaken.get(taker).get(r);
		roidsTaken.get(taker).put(r, newVal);
	}

	@Override
	public void serialize(StringBuilder sb) {
		sb.append("<battle tick=\"" + tick + "\" caption=\"" + caption + "\" message=\"" + message + "\" read=\""
				+ read + "\"  id=\"" + id + "\">\n");
		sb.append("<planet x=\"" + targetPlanet.coords.x + "\" y=\"" + targetPlanet.coords.y + "\"/>");

		sb.append("<roidsBefore>\n");
		for (Entry<Resource, Integer> e : roidsBefore.entrySet()) {
			sb.append("<res type=\"" + e.getKey() + "\" num=\"" + e.getValue() + "\"/>\n");
		}
		sb.append("</roidsBefore>\n");

		sb.append("<roidsAfter>\n");
		for (Entry<Resource, Integer> e : roidsAfter.entrySet()) {
			sb.append("<res type=\"" + e.getKey() + "\" num=\"" + e.getValue() + "\"/>\n");
		}
		sb.append("</roidsAfter>\n");

		sb.append("<roidsTaken>\n");
		for (Planet p : roidsTaken.keySet()) {
			sb.append("<planet x=\"" + p.coords.x + "\" y=\"" + p.coords.y + "\">");
			for (Entry<Resource, Integer> e : roidsTaken.get(p).entrySet()) {
				sb.append("<res type=\"" + e.getKey() + "\" num=\"" + e.getValue() + "\"/>\n");
			}
			sb.append("</planet>");
		}
		sb.append("</roidsTaken>\n");

		sb.append("<fleets>\n");
		for (Entry<FleetOrder, Set<Fleet>> e : participatingFleets.entrySet()) {

			for (Fleet f : e.getValue()) {

				sb.append("<fleetwrapper order=\"" + e.getKey() + "\">\n");
				f.serialize(sb);

				sb.append("<before>\n");
				Map<Ship, Integer> before = fleetToShipsBefore.get(f);
				for (Entry<Ship, Integer> ship : before.entrySet()) {
					sb.append("<ship type=\"" + ship.getKey().getName() + "\" num=\"" + ship.getValue() + "\"/>\n");
				}
				sb.append("</before>\n");

				sb.append("<after>\n");
				Map<Ship, Integer> after = fleetToShipsAfter.get(f);
				for (Entry<Ship, Integer> ship : after.entrySet()) {
					sb.append("<ship type=\"" + ship.getKey().getName() + "\" num=\"" + ship.getValue() + "\"/>\n");
				}
				sb.append("</after>\n");

				sb.append("</fleetwrapper>\n");
			}

		}
		sb.append("</fleets>\n");

		sb.append("</battle>");
	}
}
